﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.ComponentModel;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace Interop
{
	public abstract class Hook : IHook
	{
		#region ctors
		public Hook(HookType hookType, PresentationSource activeSource)
		{
			_HookType = hookType;
			_ActiveSource = activeSource;
			_HostHwnd = (activeSource as HwndSource).Handle;
		}

		#endregion ctors

		#region props
		public bool IsHooked { get { return _hHook != IntPtr.Zero; } }
		public IntPtr HInstance { get { return Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]); } }
		public HookProc HookProc { get; set; }
		public bool UnhandledToHost { get; set; }
		public MessageForwarding MessageForwarding { get; set; }
		protected abstract bool AllEventsAreNull { get; }
		#endregion props

		#region methods
		protected bool CanForwardMessage(MessageForwarding state, MessageForwarding test)
		{
			return ((int)state & (int)test) > 0;
		}
		public virtual void InstallHook(int threadId = 0)
		{
			InstallHook(IntPtr.Zero, threadId);
		}
		public virtual void InstallHook(IntPtr hostHwnd, int threadId = 0)
		{
			_HostHwnd = hostHwnd;
			IntPtr hInstance = (threadId == 0) ? HInstance : IntPtr.Zero;
			_hHook = NativeMethods.SetWindowsHookEx(_HookType, HookProc, hInstance, threadId);
			if (_hHook == IntPtr.Zero)
				throw new Win32Exception(Marshal.GetLastWin32Error());
		}
		public virtual void UninstallHook()
		{
			if (!NativeMethods.UnhookWindowsHookEx(_hHook))
				throw new Win32Exception(Marshal.GetLastWin32Error());
		}

		protected virtual void EnsureSubscriptionToEvents()
		{
			if (!IsHooked)
				InstallHook(_HostHwnd, _ThreadId);
		}

		protected virtual void TryUnsubscribeFromEvents()
		{
			if (AllEventsAreNull)
				ForceUnsunscribeFromEvents();
		}

		protected virtual void ForceUnsunscribeFromEvents()
		{
			if (IsHooked)
				UninstallHook();
		}
		#endregion methods

		#region events
		#endregion events

		#region fields
		protected HookType _HookType;
		protected HookProc _HookProc;
		protected IntPtr _hHook;
		protected IntPtr _HostHwnd;
		protected PresentationSource _ActiveSource;
		protected int _ThreadId;
		protected UIElement _UIElement;
		#endregion fields
	}
}
